package com.bank.backend.service.impl;

import com.bank.backend.utils.UserHolder;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.bank.backend.enums.ErrorCode;
import com.bank.backend.exception.BusinessException;
import com.bank.backend.mapper.UserMapper;
import com.bank.backend.model.entity.User;
import com.bank.backend.model.vo.UserVO;
import com.bank.backend.service.UserService;
import com.bank.backend.config.JwtProperties;
import com.bank.backend.utils.JwtUtil;
import com.bank.backend.model.dto.CustomerUpdateDTO;
import com.bank.backend.model.dto.UserPasswordUpdateDTO;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.List;
import java.util.HashMap;
import java.util.Map;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.util.DigestUtils;

import java.util.regex.Pattern;
import java.time.LocalDateTime;
/**
 * 用户服务实现类
 */
@Service
@Slf4j
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {

    @Resource
    private JwtProperties jwtProperties;

    /**
     * 手机号正则表达式
     */
    private static final String PHONE_PATTERN = "^1[3-9]\\d{9}$";

    /**
     * 身份证号正则表达式
     */
    private static final String PID_PATTERN = "^[1-9]\\d{5}(19|20)\\d{2}(0[1-9]|1[0-2])(0[1-9]|[12]\\d|3[01])\\d{3}[0-9Xx]$";

    @Override
    public UserVO userLogin(String loginId, String password, HttpServletRequest request) {
        // 1. 校验
        if (StringUtils.isAnyBlank(loginId, password)) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "参数为空");
        }
        // 2. 判断登录类型
        String loginType = getLoginType(loginId);
        // 3. 加密密码
        String encryptPassword = DigestUtils.md5DigestAsHex(password.getBytes());
        // 4. 查询用户
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        switch (loginType) {
            case "PHONE":
                queryWrapper.eq("telephone", loginId);
                break;
            case "PID":
                queryWrapper.eq("pid", loginId);
                break;
            case "ADMIN":
                queryWrapper.eq("admin_account", loginId);
                break;
            default:
                throw new BusinessException(ErrorCode.PARAMS_ERROR, "登录方式不支持");
        }
        queryWrapper.eq("password", encryptPassword);
        User user = this.baseMapper.selectOne(queryWrapper);

        // 5. 用户不存在
        if (user == null) {
            log.info("用户不存在");
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "用户不存在或密码错误");
        }

        // 6. 生成JWT
        Map<String, Object> claims = new HashMap<>();
        claims.put("userId", user.getUserId());
        claims.put("isAdmin", user.getIsAdmin());
        String token = JwtUtil.createJWT(jwtProperties.getSecretKey(), jwtProperties.getTtl(), claims);

        // 7. 返回VO
        UserVO vo = new UserVO();
        BeanUtils.copyProperties(user, vo);
        vo.setToken(token);
        return vo;
    }

    @Override
    public User getUser() {
        return UserHolder.getUser();
    }

    @Override
    public boolean userLogout(HttpServletRequest request) {
        try {
            // 清理ThreadLocal中的用户信息
            UserHolder.removeUser();
            log.info("用户退出登录成功");
            return true;
        } catch (Exception e) {
            log.error("用户退出登录失败", e);
            return false;
        }
    }


    @Override
    public UserVO getUserVO(User user) {
        if (user == null) return null;
        UserVO vo = new UserVO();
        BeanUtils.copyProperties(user, vo);
        return vo;
    }

    /**
     * 判断登录类型
     */
    private String getLoginType(String loginId) {
        if (Pattern.matches(PHONE_PATTERN, loginId)) {
            return "PHONE";
        } else if (Pattern.matches(PID_PATTERN, loginId)) {
            return "PID";
        } else {
            // 如果不是手机号或身份证号，尝试作为管理员账号查询
            return "ADMIN";
        }
    }

    @Override
    public UserVO updateCustomer(CustomerUpdateDTO updateDTO) {
        User user = getUser();
        if (user == null) {
            throw new RuntimeException("未登录或登录已过期");
        }
        if (updateDTO.getUserName() != null) {
            user.setUserName(updateDTO.getUserName());
        }
        if (updateDTO.getTelephone() != null) {
            user.setTelephone(updateDTO.getTelephone());
        }
        if (updateDTO.getAddress() != null) {
            user.setAddress(updateDTO.getAddress());
        }
        this.updateById(user);
        return getUserVO(user);
    }

    @Override
    public void updateUserPassword(UserPasswordUpdateDTO passwordUpdateDTO) {
        if (passwordUpdateDTO == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "密码修改参数不能为空");
        }
        String oldPassword = passwordUpdateDTO.getOldPassword();
        //验证新密码格式
        String newPassword = passwordUpdateDTO.getNewPassword();
        if (newPassword == null || !newPassword.matches("^\\d{6}$")) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "新密码必须是6位数字");
        }
        //验证新密码不能与原密码相同
        if (newPassword.equals(oldPassword)) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "新密码不能与原密码相同");
        }
        //获取当前登录用户
        User currentUser = UserHolder.getUser();
        //验证原密码是否正确
        String oldPasswordMd5 = DigestUtils.md5DigestAsHex(oldPassword.getBytes());
        if (!oldPasswordMd5.equals(currentUser.getPassword())) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "原密码错误");
        }
        //加密新密码并更新
        String newPasswordMd5 = DigestUtils.md5DigestAsHex(newPassword.getBytes());
        currentUser.setPassword(newPasswordMd5);
        currentUser.setUpdateTime(LocalDateTime.now());
        
        boolean success = this.updateById(currentUser);
        if (!success) {
            throw new BusinessException(ErrorCode.OPERATION_ERROR, "密码修改失败");
        }
    }
}
